package utilities;

import java.io.File;
import java.util.Iterator;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import dataFromXml.AttrConstraint;
import dataFromXml.Attribute;
import dataFromXml.DataFilter;
import dataFromXml.Eigenvalue;
import dataFromXml.FileFilter;
import dataFromXml.Join;
import dataFromXml.Match;
import dataFromXml.Modify;
import dataFromXml.ResultLimit;
import dataFromXml.Rule;
import dataFromXml.SubMatch;
import dataFromXml.Transaction;
import dataFromXml.UniqueFilter;

public class XmlConfigReader {

	Document doc;
	Transaction tree;
	
	public XmlConfigReader(String path) {
		
		SAXReader reader = new SAXReader();
		File file = new File(path);
		
		try {
			doc = reader.read(file);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			System.err.println(e.toString());
			System.exit(-1);
		}
	}
	
	@SuppressWarnings("unchecked")
	public Transaction getXMLTree() {
		
		Element root = doc.getRootElement();
		tree = new Transaction(root);
		Iterator<Element> ruleList = root.elementIterator();

		// handle rule part
		while (ruleList.hasNext()) {
			Rule ruleNode = new Rule(ruleList.next());
			tree.addRuleNode(ruleNode);
			Iterator<Element> mmList = ruleNode.getElement().elementIterator();
			
			// handle match part
			if (mmList.hasNext()) {
				Match matchNode = new Match(mmList.next());
				ruleNode.setMatchNode(matchNode);
				Iterator<Element> sjList = matchNode.getElement().elementIterator();

				// handle subMatch part and join part
				while (sjList.hasNext()) {
					Element temp = sjList.next();

					if ("SubMatch".equals(temp.getName())) {
						SubMatch submatchNode = new SubMatch(temp);
						matchNode.addSubMatchNode(submatchNode);
						Iterator<Element> fdList = submatchNode.getElement().elementIterator();
						
						// handle file filter part
						if (fdList.hasNext()) {
							FileFilter filefilterNode = new FileFilter(fdList.next());
							submatchNode.setFileFilterNode(filefilterNode);
							Iterator<Element> taaList = filefilterNode.getElement().elementIterator();
							while (taaList.hasNext()) {
								Element tempTAA = taaList.next();
								if ("TableName".equals(tempTAA.getName())) {
									filefilterNode.setTableName(tempTAA.getText());
								} else if ("AttrNames".equals(tempTAA.getName())) {
									filefilterNode.setAttrNames(tempTAA.getText());
								} else if ("AttrTypes".equals(tempTAA.getName())) {
									filefilterNode.setAttrTypes(tempTAA.getText());
								} else {
									assert false : "The form of XML file is error!";			
								}
							}
						} else {
							assert false : "The form of XML file is error!";
						}
						
						// handle data filter part
						if (fdList.hasNext()) {
							DataFilter datafilterNode = new DataFilter(fdList.next());
							submatchNode.setDataFilterNode(datafilterNode);
							Iterator<Element> uaList = datafilterNode.getElement().elementIterator();
							
							// handle unique filter part and attribute constraint filter part
							while (uaList.hasNext()) {
								Element tempUA = uaList.next();
								
								if ("UniqueFilter".equals(tempUA.getName())) {
									UniqueFilter uniquefilterNode = new UniqueFilter(tempUA);
									datafilterNode.addUniqueFilter(uniquefilterNode);
									Iterator<Element> ufList = uniquefilterNode.getElement().elementIterator();
									if (ufList.hasNext()) {
										Element tempUF = ufList.next();
										if ("UniqueAttr".equals(tempUF.getName())) {
											uniquefilterNode.setUniqueFilter(tempUF.getText());
										} else {
											assert false : "The form of XML file is error!";
										}
									} else {
										assert false : "The form of XML file is error!";
									}
								} else if ("AttrConstraintFilter".equals(tempUA.getName())) {
									AttrConstraint attrconstraintfilterNode = new AttrConstraint(tempUA);
									datafilterNode.addAttrConstraint(attrconstraintfilterNode);
									Iterator<Element> acfList = attrconstraintfilterNode.getElement().elementIterator();
									while (acfList.hasNext()) {
										Element tempACF = acfList.next();
										if ("ConstraintAttrName".equals(tempACF.getName())) {
											attrconstraintfilterNode.setConstraintAttrName(tempACF.getText());
										} else if ("ConstraintAttrExpression".equals(tempACF.getName())) {
											attrconstraintfilterNode.setConstraintAttrExpression(tempACF.getText());
										} else {
											assert false : "The form of XML file is error!";
										}
									}
								} else {
									assert false : "The form of XML file is error!";
								}
							}
						} else {
							assert false : "The form of XML file is error!";
						}
					} else if ("Join".equals(temp.getName())) {
						Join joinNode = new Join(temp);
						matchNode.setJoinNode(joinNode);
						Iterator<Element> jtjList = joinNode.getElement().elementIterator();
						while (jtjList.hasNext()) {
							Element tempJTJ = jtjList.next();
							if ("JoinType".equals(tempJTJ.getName())) {
								joinNode.setJoinType(tempJTJ.getText());
							} else if ("TableNames".equals(tempJTJ.getName())) {
								joinNode.setTableNames(tempJTJ.getText());
							} else if ("JoinAttr".equals(tempJTJ.getName())) {
								joinNode.setJoinAttr(tempJTJ.getText());
							} else {
								assert false : "The form of XML file is error!";
							}
						}
					} else {
						assert false : "The form of XML file is error!";
					}
				}
			} else {
				assert false : "The form of XML file is error!";
			}
			
			// handle modify part			
			if (mmList.hasNext()) {
				Modify modifyNode = new Modify(mmList.next());
				ruleNode.setModifyNode(modifyNode);
				Iterator<Element> erList = modifyNode.getElement().elementIterator();
			
				// handle eigenvalue part and result limit part
				while (erList.hasNext()) {
					Element temp = erList.next();
					
					if ("Eigenvalue".equals(temp.getName())) {
						Eigenvalue eigenvalueNode = new Eigenvalue(temp);
						modifyNode.addEigenvalueNode(eigenvalueNode);
						Iterator<Element> eeeList = eigenvalueNode.getElement().elementIterator();
						while (eeeList.hasNext()) {
							Element tempEEE = eeeList.next();
							if ("EigenAttr".equals(tempEEE.getName())) {
								eigenvalueNode.setEigenAttr(tempEEE.getText());
							} else if ("EigenType".equals(tempEEE.getName())) {
								eigenvalueNode.setEigenType(tempEEE.getText());
							} else if ("EigenName".equals(tempEEE.getName())) {
								eigenvalueNode.setEigenName(tempEEE.getText());
							} else {
								assert false : "The form of XML file is error!";
							}
						}
					} else if ("ResultLimit".equals(temp.getName())) {
						ResultLimit resultlimitNode = new ResultLimit(temp);
						modifyNode.setResultLimitNode(resultlimitNode);
						Iterator<Element> taList = resultlimitNode.getElement().elementIterator();
						
						// handle table name part
						if (taList.hasNext()) {
							Element tempTN = taList.next();
							if ("TableName".equals(tempTN.getName())) {
								resultlimitNode.setTableName(tempTN.getText());
							} else {
								assert false : "The form of XML file is error!";
							}
						} else {
							assert false : "The form of XML file is error!";
						}
						
						//  handle attribute part
						while (taList.hasNext()) {
							Attribute attributeNode = new Attribute(taList.next());
							resultlimitNode.addAttrNode(attributeNode);
							Iterator<Element> rafList = attributeNode.getElement().elementIterator();
							
							while (rafList.hasNext()) {
								Element tempRAF = rafList.next();
								if ("ResultLimitAttr".equals(tempRAF.getName())) {
									attributeNode.setResultLimitAttr(tempRAF.getText());
								} else if ("AttrExpression".equals(tempRAF.getName())) {
									attributeNode.setAttrExpression(tempRAF.getText());
								} else if ("Function".equals(tempRAF.getName())) {
									attributeNode.setFunction(tempRAF.getText());
								} else {
									assert false : "The form of XML file is error!";
								}
							}
						}
					} else {
						assert false : "The form of XML file is error!";
					}
				}
			} else {
				assert false : "The form of XML file is error!";
			}
		}
		return tree;
	}
}
